<script>
import { cloneDeep as clone } from 'lodash'
import Treeselect, { LOAD_ROOT_OPTIONS, LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect'
import $http from '@/api/server/http'

const IS_ROOT = 1

export default {
  name: 'ZlstTreeSelectWrapper',
  components: {
    Treeselect
  },
  props: {
    apiKey: {
      required: true,
      type: String,
      default: ''
    },
    labelKey: {
      required: true,
      type: String,
      default: 'label'
    },
    idKey: {
      required: true,
      type: String,
      default: 'id'
    },
    lazy: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      value: null,
      model: null,
      modelWrap: null
    }
  },
  methods: {
    loadOptions({ action, parentNode, callback }) {
      if (action === LOAD_ROOT_OPTIONS) {
        // 正常模式和懒加载模式的参数不同
        const args = [this.apiKey, {}, {
          headers: {
            Authorization: 'Bearer ' + this.$store.state.user.token,
            clientId: this.$store.state.user.clientId,
            realm: this.$store.state.user.realm
          }
        }]
        $http.getRestful(...args)
          .then(res => {
            if (res.data.resultCode !== 0) {
              callback()
              return
            }
            this.modelWrap = this.wrapData4ModeNormal(res.data.data)
            callback()
          })
          .catch(err => {
            console.log(err)
            callback()
          })
      } else if (action === LOAD_CHILDREN_OPTIONS) {
        console.log(222)
        $http.getRestful(this.apiKey, {}, {
          headers: {
            Authorization: 'Bearer ' + this.$store.state.user.token,
            clientId: this.$store.state.user.clientId,
            realm: this.$store.state.user.realm
          }
        })
          .then(res => {
            if (res.data.resultCode !== 0) {
              callback()
              return
            }
            parentNode.children = this.wrapData4ModeLazy(res.data.data)
            callback()
          })
          .catch(err => {
            console.log(err)
            callback()
          })
      }
    },
    // 普通模式，即一次性取出全部数据，再将数据封装成一颗树
    wrapData4ModeNormal(fullData) {
      this.model = fullData
      // 深拷贝一份，进行数据封装
      const temp = clone(fullData).map(item => {
        if (item.hasOwnProperty(this.idKey)) {
          item.id = item[this.idKey]
        }
        if (item.hasOwnProperty(this.labelKey)) {
          item.label = item[this.labelKey]
        }
        return item
      })
      // 找出根节点
      const result = this.checkout(temp, item => item.isRoot === IS_ROOT)
      const roots = result.filters
      let rests = result.rests
      // 递归函数，形成父子关系
      const travese = parents => {
        if (!rests.length) {
          return
        }
        parents.forEach(parent => {
          const result = this.checkout(rests, item => (item.parentId === parent.id))
          const filters = result.filters
          rests = result.rests
          if (filters.length) {
            parent.children = filters
          } else if (this.lazy) {
            parent.children = null
          }
          travese(filters)
        })
      }
      travese(roots)
      return roots
    },
    // 懒加载模式，即一次只加载一层的数据，点开节点时再
    wrapData4ModeLazy(fullData) {
      // 深拷贝一份，进行数据封装
      const temp = clone(fullData).map(item => {
        if (item.hasOwnProperty(this.idKey)) {
          item.id = item[this.idKey]
        }
        if (item.hasOwnProperty(this.labelKey)) {
          item.label = item[this.labelKey]
        }
        item.children = null
        return item
      })
      return temp
    },
    // 从数组检出筛选的数据
    // 返回两个数组，一个是符合筛选条件的数组，一个是原数组中除去筛选条件剩下的数组
    checkout(rests = [], iterator) {
      const filters = []
      for (let i = rests.length - 1; i--;) {
        const item = rests[i]
        if (iterator(item)) {
          filters.push(...rests.splice(i, 1))
        }
      }
      return { filters, rests }
    }
  },
  render() {
    return (
      <treeselect
        {...{
          attrs: {
            ...this.$attrs,
            searchNested: true,
            value: this.value,
            options: this.modelWrap,
            loadOptions: this.loadOptions
          },
          on: this.$listeners,
          scopedSlots: this.$scopedSlots
        }}
      />
    )
  }
}
</script>

<style lang="scss" scoped>
  .vue-treeselect {
    font-size: 14px;
    color: #333;
  }
  /deep/ .vue-treeselect__label {
    font-weight: normal;
  }
</style>
